<template>
  <div class="monitoring-container">
    <h2>大学环境监测数据</h2>
    
    <!-- 左侧选择区域 -->
    <div class="select-container">
      <select v-model="selectedUni" @change="updateCharts">
        <option value="">请选择大学</option>
        <option v-for="uni in universities" :value="uni.id" :key="uni.id">
          {{ uni.name }}
        </option>
      </select>
    </div>
    
    <!-- 右侧图表区域 -->
    <div class="charts-container">
      <!-- 温度图表 -->
      <div class="chart-box">
        <h3>温度 (℃)</h3>
        <canvas ref="tempCanvas" class="chart-canvas"></canvas>
      </div>
      
      <!-- PM2.5图表 -->
      <div class="chart-box">
        <h3>PM2.5 (μg/m³)</h3>
        <canvas ref="pm25Canvas" class="chart-canvas"></canvas>
      </div>
      
      <!-- PM10图表 -->
      <div class="chart-box">
        <h3>PM10 (μg/m³)</h3>
        <canvas ref="pm10Canvas" class="chart-canvas"></canvas>
      </div>
      
      <!-- TSP图表 -->
      <div class="chart-box">
        <h3>TSP (μg/m³)</h3>
        <canvas ref="tspCanvas" class="chart-canvas"></canvas>
      </div>
      
      <!-- 湿度图表 -->
      <div class="chart-box full-width">
        <h3>湿度 (%)</h3>
        <canvas ref="humidityCanvas" class="chart-canvas"></canvas>
      </div>
    </div>
  </div>
</template>

<script>
export default {
  data() {  // 存储组件需要用的数据
    return {
      selectedUni: '',  // 选中的大学ID（比如选了北京大学，这里就是"pku"）
      universities: [  // 大学列表数据
        { id: 'pku', name: '中北大学' },
        { id: 'tsinghua', name: '兰州理工' },
        { id: 'fudan', name: '太原理工大学' },
        { id: 'zju', name: '山西农大主体育场' }
      ],
      environmentData: {},  // 存放所有大学的环境数据（后面会生成模拟数据）
      contexts: {}  // 存放每个canvas的「画笔」（绘图上下文）
    }
  },
  
  mounted() {  // 组件加载完成后自动执行的代码（初始化工作）
    this.initData();  // 生成模拟数据
    this.initCanvasContexts();  // 准备好所有画布的「画笔」
  },
  
  methods: {  // 存放各种功能方法（比如生成数据、画图表）
    // 1. 初始化模拟数据（给每个大学生成假数据）
    initData() {
      // 遍历所有大学，给每个大学生成数据
      this.universities.forEach(uni => {
        this.environmentData[uni.id] = this.generateMockData();
      });
    },
    
    // 2. 准备画布的「画笔」（获取每个canvas的绘图上下文）
    initCanvasContexts() {
      // 给每个画布获取一个「画笔」（context），后面用这个画笔在画布上画
      this.contexts.temp = this.$refs.tempCanvas.getContext('2d');
      this.contexts.pm25 = this.$refs.pm25Canvas.getContext('2d');
      this.contexts.pm10 = this.$refs.pm10Canvas.getContext('2d');
      this.contexts.tsp = this.$refs.tspCanvas.getContext('2d');
      this.contexts.humidity = this.$refs.humidityCanvas.getContext('2d');
      
      // 设置每个画布的实际尺寸（避免画图模糊）
      Object.values(this.$refs).forEach(canvas => {
        canvas.width = canvas.offsetWidth;  // 宽度等于画布在页面上显示的宽度
        canvas.height = 200;  // 固定高度200px
      });
    },
    
    // 3. 生成模拟数据（假数据，模拟24小时的环境监测值）
    generateMockData() {
      const data = [];
      // 生成24小时数据（从0点到23点）
      for (let i = 0; i < 24; i++) {
        const hour = i < 10 ? `0${i}:00` : `${i}:00`;  // 时间格式：00:00、01:00...23:00
        data.push({
          time: hour,  // 时间
          temperature: 15 + Math.random() * 10,  // 温度：15-25℃（随机）
          pm25: Math.random() * 100,  // PM2.5：0-100μg/m³（随机）
          pm10: Math.random() * 150,  // PM10：0-150μg/m³（随机）
          tsp: Math.random() * 200,   // TSP：0-200μg/m³（随机）
          humidity: 30 + Math.random() * 50  // 湿度：30-80%（随机）
        });
      }
      return data;  // 返回24小时的数据数组
    },
    
    // 4. 选完大学后更新所有图表
    updateCharts() {
      if (!this.selectedUni) return;  // 如果没选大学，直接退出
      
      const data = this.environmentData[this.selectedUni];  // 获取选中大学的数据
      if (!data) return;  // 如果没数据，直接退出
      
      // 调用画图方法，分别画5个图表
      this.drawChart(
        this.contexts.temp,  // 温度图表的画笔
        data,  // 数据
        'temperature',  // 要画的字段（温度）
        '#ff6384',  // 线条颜色（粉色）
        this.$refs.tempCanvas  // 温度画布
      );
      
      // 画PM2.5图表（参数类似，只是字段和颜色不同）
      this.drawChart(
        this.contexts.pm25, 
        data, 
        'pm25', 
        '#36a2eb',  // 蓝色
        this.$refs.pm25Canvas
      );
      
      // 画PM10图表
      this.drawChart(
        this.contexts.pm10, 
        data, 
        'pm10', 
        '#ffcd56',  // 黄色
        this.$refs.pm10Canvas
      );
      
      // 画TSP图表
      this.drawChart(
        this.contexts.tsp, 
        data, 
        'tsp', 
        '#4bc0c0',  // 青色
        this.$refs.tspCanvas
      );
      
      // 画湿度图表
      this.drawChart(
        this.contexts.humidity, 
        data, 
        'humidity', 
        '#9966ff',  // 紫色
        this.$refs.humidityCanvas
      );
    },
    
    // 5. 通用画图方法（核心！用这个方法画所有图表）
    drawChart(ctx, data, property, color, canvas) {
      // 第一步：清空画布（每次画新图前，先擦掉旧图）
      ctx.clearRect(0, 0, canvas.width, canvas.height);
      
      // 第二步：设置图表的内边距（避免内容贴边）
      const padding = { top: 20, right: 20, bottom: 30, left: 40 };
      // 计算实际绘图区域的宽高（减去内边距）
      const chartWidth = canvas.width - padding.left - padding.right;
      const chartHeight = canvas.height - padding.top - padding.bottom;
      
      // 第三步：处理数据范围（让图表能完整显示所有数据）
      const values = data.map(item => item[property]);  // 提取当前字段的所有值（比如所有温度值）
      const maxValue = Math.max(...values) * 1.1;  // 最大值（加10%余量，避免顶到边）
      const minValue = Math.min(...values) * 0.9;  // 最小值（减10%余量）
      const valueRange = maxValue - minValue;  // 数据范围（最大值-最小值）
      
      // 第四步：计算X轴的步长（每个数据点之间的水平距离）
      const pointCount = data.length;  // 数据点数量（24个，对应24小时）
      const xStep = chartWidth / (pointCount - 1);  // 每个点之间的距离
      
      // 第五步：画坐标轴（X轴和Y轴）
      ctx.beginPath();  // 开始画画
      ctx.strokeStyle = '#ddd';  // 线条颜色（浅灰色）
      // 画X轴（横线）
      ctx.moveTo(padding.left, padding.top + chartHeight);  // 起点（左下角）
      ctx.lineTo(padding.left + chartWidth, padding.top + chartHeight);  // 终点（右下角）
      // 画Y轴（竖线）
      ctx.moveTo(padding.left, padding.top);  // 起点（左上角）
      ctx.lineTo(padding.left, padding.top + chartHeight);  // 终点（左下角）
      ctx.stroke();  // 执行画线
      
      // 第六步：画网格线（辅助线，让图表更易读）
      ctx.beginPath();
      ctx.strokeStyle = '#f0f0f0';  // 网格线颜色（更浅的灰色）
      // 画水平线（5条，横向分割图表）
      for (let i = 0; i <= 5; i++) {
        const y = padding.top + (chartHeight * (1 - i/5));  // 计算每条线的Y坐标
        ctx.moveTo(padding.left, y);  // 起点（左边）
        ctx.lineTo(padding.left + chartWidth, y);  // 终点（右边）
        
        // 在Y轴上标数值（比如温度的15℃、20℃）
        ctx.fillStyle = '#666';  // 文字颜色
        ctx.textAlign = 'right';  // 文字靠右对齐
        ctx.textBaseline = 'middle';  // 文字垂直居中
        ctx.fillText(
          Math.round((minValue + (valueRange * i/5)) * 10) / 10,  // 计算显示的数值（保留1位小数）
          padding.left - 5,  // 文字位置（Y轴左边）
          y  // 文字的Y坐标（和水平线对齐）
        );
      }
      // 画垂直线（每4小时一条，纵向分割图表）
      for (let i = 0; i < pointCount; i += 4) {
        const x = padding.left + (i * xStep);  // 计算每条线的X坐标
        ctx.moveTo(x, padding.top);  // 起点（上边）
        ctx.lineTo(x, padding.top + chartHeight);  // 终点（下边）
        
        // 在X轴上标时间（比如00:00、04:00）
        ctx.fillStyle = '#666';
        ctx.textAlign = 'center';  // 文字居中对齐
        ctx.textBaseline = 'top';  // 文字靠上对齐
        ctx.fillText(
          data[i].time,  // 显示的时间
          x,  // 文字的X坐标（和垂直线对齐）
          padding.top + chartHeight + 5  // 文字位置（X轴下方）
        );
      }
      ctx.stroke();  // 执行画网格线
      
      // 第七步：画数据线（折线）
      ctx.beginPath();
      data.forEach((item, i) => {
        // 计算每个数据点的坐标（把数据值转换成画布上的像素位置）
        const x = padding.left + (i * xStep);  // X坐标（根据时间计算）
        // Y坐标（根据数据值计算，值越大Y越小，因为画布Y轴向下增长）
        const y = padding.top + chartHeight - 
          ((item[property] - minValue) / valueRange * chartHeight);
        
        if (i === 0) {
          ctx.moveTo(x, y);  // 第一个点：起点
        } else {
          ctx.lineTo(x, y);  // 后续点：连线
        }
      });
      ctx.strokeStyle = color;  // 线条颜色（传入的颜色，比如粉色）
      ctx.lineWidth = 2;  // 线条粗细
      ctx.stroke();  // 执行画折线
      
      // 第八步：画数据点（每个数据的小圆点）
      data.forEach((item, i) => {
        const x = padding.left + (i * xStep);  // 同折线的X坐标
        const y = padding.top + chartHeight - 
          ((item[property] - minValue) / valueRange * chartHeight);  // 同折线的Y坐标
        
        ctx.beginPath();
        ctx.arc(x, y, 3, 0, Math.PI * 2);  // 画圆（圆心x,y，半径3px，0到360度）
        ctx.fillStyle = color;  // 圆点颜色
        ctx.fill();  // 填充圆（画实心点）
      });
    }
  }
}

</script>

<style scoped>
/* 整个组件的容器 */
.monitoring-container {
  max-width: 1200px;  /* 最大宽度，避免在宽屏上太散 */
  margin: 20px auto;  /* 上下边距20px，左右居中 */
  padding: 0 20px;    /* 左右内边距，避免贴边 */
  font-family: Arial, sans-serif;  /* 字体 */
}

/* 选择框的容器 */
.select-container {
  margin-bottom: 20px;  /* 距离下面的图表20px */
}

/* 下拉选择框的样式 */
select {
  padding: 8px 12px;    /* 内边距，让选择框大一点 */
  border: 1px solid #ddd;  /* 边框（浅灰色） */
  border-radius: 4px;    /* 圆角 */
  font-size: 14px;       /* 字体大小 */
  min-width: 200px;      /* 最小宽度，避免太窄 */
}

/* 图表区域的容器（用网格布局排列图表） */
.charts-container {
  display: grid;               /* 开启网格布局 */
  grid-template-columns: repeat(2, 1fr);  /* 每行2列，每列宽度相等 */
  gap: 20px;                   /* 图表之间的间距20px */
}

/* 每个图表的小盒子 */
.chart-box {
  border: 1px solid #eee;      /* 边框（更浅的灰色） */
  border-radius: 6px;          /* 圆角 */
  padding: 15px;               /* 内边距 */
  background-color: #fff;      /* 白色背景 */
  box-shadow: 0 2px 4px rgba(0,0,0,0.05);  /* 轻微阴影，立体感 */
}

/* 让湿度图表占满一行 */
.full-width {
  grid-column: 1 / -1;  /* 从第1列到最后一列 */
}

/* 标题样式 */
h2, h3 {
  color: #333;  /* 深灰色文字 */
  margin-top: 0;  /* 去掉默认的上边距 */
}

h2 {
  font-size: 20px;    /* 大标题稍大 */
  margin-bottom: 20px;  /* 距离下面20px */
}

h3 {
  font-size: 16px;    /* 小标题稍小 */
  margin-bottom: 15px;  /* 距离下面的图表15px */
  color: #666;        /* 颜色稍浅 */
}

/* 画布样式 */
.chart-canvas {
  width: 100%;    /* 宽度占满盒子 */
  height: 200px;  /* 固定高度200px */
}
</style>
